import struct
import socket
'''
ipv4格式：
版本[0:3]  首部长度[4:7]  服务类型[8:15]  总长度[16:31]
标识[0:15] 标志[16:18]  片偏移[19:31]
生存时间[0:7]  协议[8:15]  首部检验和[16:31]
源地址[0:31]
目的地址[0:31]
数据部分。。。。
'''


class IPv4:
    def __init__(self, IP_version, IP_head_len, server_kind, Total_len,
                 identification, flag, Fragment_offset, TTL, protocol, checkSum, src_ip, dst_ip, data):
        self.IP_version = IP_version  # IP版本，IPv4默认为4
        self.IP_head_len = IP_head_len  # IP头部长度，这里4bytes为单位，要除4
        # -->第一个字节 char "B"
        self.Server_kind = server_kind  # 服务类型,默认0 -->第二字节 char "B"
        self.Total_len = Total_len  # 总长度 bytes单位-->第三四字节 unsignedshort "H"
        self.identification = identification  # 标识 初始值1 --> 第五六字节 unsignedshort "H"
        # 标志 标志字段中的最低位记为 MF(More Fragment).MF=1即表示后面"还有分片"的数据报.标志字段中间的一位记为DF(Don't Fragment),意思是"不能分片",
        self.flag = flag
        self.Fragment_offset = Fragment_offset  # 片偏移 无分片则为0
        # -->第七八字节(3+13) unsignedchar "H"
        self.TTL = TTL                    # 生存时间 第九字节 char "B"
        self.protocol = protocol  # 协议 第十字节 char "B"
        self.checkSum = checkSum  # 首部检验和 第11，12字节 unsignedshort "H"
        self.src_ip = socket.inet_pton(socket.AF_INET, src_ip)  # 源地址ip 第13，14，15，16字节 unsignedint "I"
        self.dst_ip = socket.inet_pton(socket.AF_INET, dst_ip)  # 目的地址ip 第17，18，19，20字节 unsignedint "I"
        self.data = data  # 数据部分 以四字节为单位吧 拼接一下


    def makeCheckSum(self,msg):
        s = 0
        for i in range(0,len(msg),2):
            w = (msg[i] << 8) + (msg[i+1])
            s = s+w
        s = (s>>16) + (s & 0xffff)
        s = ~s & 0xffff
        return s
    

    def getHeaderPack(self):
        header = struct.pack("!BBHHHBBH4s4s",
                             self.IP_version << 4 | self.IP_head_len,
                             self.Server_kind,
                             self.Total_len,
                             self.identification,
                             self.flag << 13 | self.Fragment_offset,
                             self.TTL,
                             self.protocol,
                             self.checkSum,
                             self.src_ip,
                             self.dst_ip
                             )
        self.checkSum = self.makeCheckSum(header)
        header = struct.pack("!BBHHHBBH4s4s",
                             self.IP_version << 4 | self.IP_head_len,
                             self.Server_kind,
                             self.Total_len,
                             self.identification,
                             self.flag << 13 | self.Fragment_offset,
                             self.TTL,
                             self.protocol,
                             self.checkSum,
                             self.src_ip,
                             self.dst_ip
                             )
        return header
    def getPack(self):
        header = self.getHeaderPack()
        return header+bytes(self.data)

if __name__ == '__main__':
    myIpv4 = IPv4(IP_version=4,
                IP_head_len=5,
                server_kind=0,
                Total_len=20,
                identification=6,##TCP是6
                flag=2,#010-->不分片，无分片
                Fragment_offset=0,#无分片=0
                TTL=1,# TTL 的初始值设为 1，则表示这个数据报只能在本局域网中传送
                protocol=6,#TCP 的协议号为 6
                checkSum=0,#校验和先初始化为0，后计算填充
                src_ip=socket.inet_aton("192.168.1.2"),
                dst_ip=socket.inet_aton("192.168.1.3"),
                data=None
                )
    header = myIpv4.getHeaderPack()
    print(header)
